package org.littlesun.management.address;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

import lombok.AllArgsConstructor;

import org.apache.commons.lang3.StringUtils;

@AllArgsConstructor
public class RoadMatcher {

	private MatchResult parent;
	private CityZone cityZone;
	
	public RoadMatcher(CityZone cityZone) {
		this(null, cityZone);
	}
	
	public MatchResult match(String text) {
		MatchResult result = matchRoadNameFirstChar(text);
		if (result.isSuccess() == false && text.isEmpty()) {
			result.addSuggestions(getFirstCharSuggestions());
			return result;
		}
		result = matchRoadName(text);
		if (result.isSuccess() == false) {
			result = matchRoadAlias(text);
		}
		if (result.isSuccess() == false) {
			result.addSuggestions(getSuggestions());
		}
		return result;
	}
	
	private MatchResult matchRoadNameFirstChar(String text) {
		text = text.trim();
		for(Road road : cityZone.getRoads()) {
			String roadFirstChar = String.valueOf(road.getName().charAt(0));
			if (StringUtils.startsWith(text, roadFirstChar)) {
				return new MatchResult(parent, road, roadFirstChar, text.substring(roadFirstChar.length()));
			}
		}
		return new MatchResult(parent, null, "", text);
	}
	
	private MatchResult matchRoadName(String text) {
		text = text.trim();
		for(Road road : cityZone.getRoads()) {
			if (StringUtils.startsWith(text, road.getName())) {
				return new MatchResult(parent, road, road.getName(), text.substring(road.getName().length()));
			}
		}
		return new MatchResult(parent, null, "", text);
	}

	private MatchResult matchRoadAlias(String text) {
		text = text.trim();
		for(Road road : cityZone.getRoads()) {
			for(String alias : road.getAliases()) {
				if (StringUtils.startsWith(text, alias)) {
					return new MatchResult(parent, road, alias, text.substring(alias.length()));
				}
			}
		}
		return new MatchResult(parent, null, "", text);
	}

	protected List<String> getSuggestions() {
		String matchedOrginalText = parent == null? "" : parent.getFullMatchedOrginalText();
		List<String> names = new ArrayList<String>();
		for(Road road : cityZone.getRoads()) {
			names.add(matchedOrginalText + road.getName());
		}
		return names;
	}

	protected List<String> getFirstCharSuggestions() {
		String matchedOrginalText = parent == null? "" : parent.getFullMatchedOrginalText();
		List<String> names = new ArrayList<String>();
		Set<String> roadFirstChars = new HashSet<String>();
		for(Road road : cityZone.getRoads()) {
			String roadFirstChar = String.valueOf(road.getName().charAt(0));
			if (!roadFirstChars.contains(roadFirstChar)) {
				names.add(matchedOrginalText + roadFirstChar);
				roadFirstChars.add(roadFirstChar);
			}
		}
		return names;
	}

}
